import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { TaskCategory } from './entities/task-category.entity';
import { Task } from './entities/task.entity';
import { CreateTaskCategoryDto } from './dto/create-task-category.dto';
import { UpdateTaskCategoryDto } from './dto/update-task-category.dto';
import { TaskCategoryDto } from './dto/task-category.dto';

@Injectable()
export class TaskCategoriesService {
  constructor(
    @InjectRepository(TaskCategory)
    private taskCategoryRepository: Repository<TaskCategory>,
    @InjectRepository(Task)
    private taskRepository: Repository<Task>,
  ) {}

  async create(createTaskCategoryDto: CreateTaskCategoryDto): Promise<TaskCategoryDto> {
    const taskCategory = this.taskCategoryRepository.create(createTaskCategoryDto);
    const savedCategory = await this.taskCategoryRepository.save(taskCategory);
    return this.mapToDto(savedCategory);
  }

  async findAll(page = 1, pageSize = 20): Promise<{ data: TaskCategoryDto[]; total: number }> {
    const [categories, total] = await this.taskCategoryRepository.findAndCount({
      where: { isDeleted: false },
      skip: (page - 1) * pageSize,
      take: pageSize,
    });

    return {
      data: categories.map((category) => this.mapToDto(category)),
      total,
    };
  }

  async findOne(id: string): Promise<TaskCategoryDto> {
    const taskCategory = await this.taskCategoryRepository.findOne({
      where: { id, isDeleted: false },
    });

    if (!taskCategory) {
      throw new NotFoundException(`Task category with ID ${id} not found`);
    }

    return this.mapToDto(taskCategory);
  }

  async update(id: string, updateTaskCategoryDto: UpdateTaskCategoryDto): Promise<TaskCategoryDto> {
    const taskCategory = await this.findOneEntity(id);

    // Update the entity with the new values
    this.taskCategoryRepository.merge(taskCategory, updateTaskCategoryDto);

    const updatedCategory = await this.taskCategoryRepository.save(taskCategory);
    return this.mapToDto(updatedCategory);
  }

  async remove(id: string): Promise<void> {
    const taskCategory = await this.findOneEntity(id);

    // Check if category is being used by any non-deleted tasks
    const tasksUsingCategory = await this.taskRepository.count({
      where: {
        taskCategoryId: id,
        isDeleted: false,
      },
    });

    if (tasksUsingCategory > 0) {
      throw new ConflictException(
        `Cannot delete task category that is being used by ${tasksUsingCategory} active tasks`,
      );
    }

    // Soft delete by setting isDeleted to true
    taskCategory.isDeleted = true;
    await this.taskCategoryRepository.save(taskCategory);
  }

  private async findOneEntity(id: string): Promise<TaskCategory> {
    const taskCategory = await this.taskCategoryRepository.findOne({
      where: { id, isDeleted: false },
    });

    if (!taskCategory) {
      throw new NotFoundException(`Task category with ID ${id} not found`);
    }

    return taskCategory;
  }

  private mapToDto(taskCategory: TaskCategory): TaskCategoryDto {
    const dto = new TaskCategoryDto();
    dto.id = taskCategory.id;
    dto.name = taskCategory.name;
    dto.description = taskCategory.description;
    dto.isDeleted = taskCategory.isDeleted;
    return dto;
  }
}
